﻿/* 2012/4/15 */
using System;
using System.Collections.Generic;
using System.Text;

namespace Cosmos.Shortcuts
{    
    [Flags]
    public enum Direction : int
    {
        Center = 0x0,
        North = 0x1,
        West = 0x2,
        South = 0x4,
        East = 0x8,
        NorthWest = 0x3,
        SouthWest = 0x6,
        NorthEast = 0x9,
        SouthEast = 0xC,
    };

    /// <summary>
    /// The direction of moving.
    /// </summary>
    public struct MoveDirection
    {
        int _directionValue;

        public MoveDirection(Direction direction)
            : this()
        {
            Direction = direction;
        }

        /// <summary>
        /// Get or set the direction value of this direction.
        /// </summary>
        public Direction Direction
        {
            get { return (Direction)_directionValue; }
            set { _directionValue = (int)value; }
        }
        /// <summary>
        /// Determines whether this direction is center(without any direction).
        /// </summary>
        public bool IsCenter
        {
            get { return Direction == Direction.Center; }
        }
        /// <summary>
        /// Determines whether this direction is a vertical direction.
        /// </summary>
        public bool IsVertical
        {
            get { return Direction == Direction.South || Direction == Direction.North; }
        }
        /// <summary>
        /// Determines whether this direction is a horizontal direction.
        /// </summary>
        public bool IsHorizontal
        {
            get { return Direction == Direction.East || Direction == Direction.West; }
        }
        /// <summary>
        /// Determines whether this direction is a principal direction.
        /// </summary>
        public bool IsPrincipal
        {
            get { return IsVertical || IsHorizontal; }
        }
        /// <summary>
        /// Determines whether the specified direction is an adjacent direction of this direction.
        /// </summary>
        public bool IsAdjacent(MoveDirection direction)
        {
            Direction principalDirection;
            Direction viceDirection;
            if (IsPrincipal && !direction.IsPrincipal)
            {
                principalDirection = Direction;
                viceDirection = direction.Direction;
            }
            else if (!IsPrincipal && direction.IsPrincipal)
            {
                principalDirection = direction.Direction;
                viceDirection = Direction;
            }
            else
            {
                return false;
            }
            return (principalDirection == (principalDirection & viceDirection)) && (viceDirection == (principalDirection | viceDirection));
        }
        /// <summary>
        /// Determines whether the specified direction is the same direction of this direction.
        /// </summary>
        public bool Equals(MoveDirection direction)
        {
            return Direction == direction.Direction;
        }
        /// <summary>
        /// Get the reverse direction of this direction.
        /// </summary>
        public MoveDirection Reverse()
        {
            int valueNumber = (int)_directionValue;
            valueNumber <<= 2;
            if (valueNumber > 0xF)
                valueNumber >>= 4;
            return new MoveDirection((Direction)valueNumber);
        }
        /// <summary>
        /// Get the left direction of this direction.
        /// </summary>
        public MoveDirection Left()
        {
            int valueNumber = (int)_directionValue;
            int resultNumber = valueNumber << 1;
            if (resultNumber > 0xF)
                resultNumber = valueNumber >> 3;
            return new MoveDirection((Direction)resultNumber);
        }
        /// <summary>
        /// Get the right direction of this direction.
        /// </summary>
        public MoveDirection Right()
        {
            int valueNumber = (int)_directionValue;
            int resultNumber = valueNumber >> 1;
            if (resultNumber == 0x0)
                resultNumber = valueNumber << 3;
            return new MoveDirection((Direction)resultNumber);
        }
    }
}
